package org.sja.log2traffic.logLineParsers;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.sja.log2traffic.ILogDataModyficator;
import org.sja.log2traffic.dataStructures.DateAndResponseTimeEntity;
import org.sja.log2traffic.dataStructures.ILogData;
import org.sja.log2traffic.dataStructures.INewLogInfo;

/**
 * This is example of parser for demo application event log.
 * 
 * This log look like below:
 * 2011-10-06 00:00:07,623 [THREAD-4] myApp/servlet_3 was called successfully
 * 2011-10-06 00:00:08,207 [THREAD-4] RESPONSE_TIME:584
 * 2011-10-06 00:00:35,802 [THREAD-2] myApp/servlet_2 was called successfully
 * 2011-10-06 00:00:37,017 [THREAD-2] RESPONSE_TIME:1215
 * etc.
 * 
 * @author Stanislaw Jagiella
 *
 */

public class SimpleLogLineParser implements ILogDataModyficator {

	/**
	 * Format such date like 2011-10-06 00:00:07,623
	 */
	private final SimpleDateFormat DATE_FORMAT_WITH_MILIS = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS");
	
	/**
	 * Parse every first line of log.
	 * Example:
	 * 2011-10-06 00:00:07,623 [THREAD-4] myApp/servlet_3 was called successfully 
	 */
	private Pattern patternBefore = Pattern.compile(".{23} \\[(THREAD-[0-9]+)\\] myApp/servlet_([0-9]+) was called successfully");

	/**
	 * Parse every second line of log file:
	 * Example:
	 * 2011-10-06 00:00:08,207 [THREAD-4] RESPONSE_TIME:584
	 * 
	 */
	private Pattern patternAfter = Pattern.compile(".{23} \\[(THREAD-[0-9]+)\\] RESPONSE_TIME:([0-9]+)");

	private Map<String, String> responses = new HashMap<String, String>();


	@Override
	public void modifyRawData(ILogData[] logData, String line) {
		boolean isAnyLogDataIntrested = false;
		long time = 0;
		/* We are not interested in lines not started with year 20xx*/
		if (line.startsWith("20")) {
			/* Fast way to parse date*/
			String timeInString = line.substring(0, 23);
			time = stringWithMilisToLong(timeInString);
			for (ILogData logDataItem : logData) {
				INewLogInfo newLogInfo = logDataItem.getLogInfo(time);
				if (newLogInfo != null) {
					isAnyLogDataIntrested = true;
				}
			}
		}
		/* if any data structure was interested in. We should make real (slow) parsing*/
		if (isAnyLogDataIntrested) {
			Matcher m1 = patternBefore.matcher(line);
			if (m1.matches()) {
				// collect information from first line
				String threadName = m1.group(1).trim();
				String serviceId = m1.group(2).trim();
				// temporary store information in hashMap
				responses.put(threadName, serviceId);
			} else {
				Matcher m2 = patternAfter.matcher(line);
				if (m2.matches()) {
					String threadName = m2.group(1).trim();
					// check if there is corresponding first line. If yes - get reference and remove it
					String serviceId = responses.remove(threadName);
					if (serviceId != null) {
						String responseTime = m2.group(2).trim();
						for (ILogData logDataItem : logData) {
							INewLogInfo newLogInfo = logDataItem.getLogInfo(time);
							if (newLogInfo != null) {
								// the most important place: store information in data structure
								newLogInfo.accept("Feature_" + serviceId, new DateAndResponseTimeEntity(time, Long.parseLong(responseTime)));
							}
						}
					}
				}
			}
		}
	}
	
	private Long stringWithMilisToLong(String dateStr) {
		try {
			return DATE_FORMAT_WITH_MILIS.parse(dateStr).getTime();
		} catch (ParseException e) {
			e.printStackTrace();
			return null;
		}
	}	

}
